package team.lourd.network.system.utils.file;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import team.lourd.network.system.config.FileStorageProperties;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Base64;

/** 
* @Description: 处理文件上传的服务
* @Author: Lourd 
* @Date: 2019/1/17 
*/
@Service
public class FileStorageService {

    private final Path fileStorageLoaction;

    private FileStorageProperties fileStorageProperties;

    String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf(".");
        if(dotIndex < 0) {
            return null;
        }
        return fileName.substring(dotIndex+1);
    }

    boolean isValidExtension(String fileName)
            throws InvalidFileException {
        String fileExtension = getFileExtension(fileName);

        if (fileExtension == null) {
            throw new InvalidFileException("No File Extension");
        }

        fileExtension = fileExtension.toLowerCase();

        for (String validExtension : this.fileStorageProperties.getUploadExtensions().split(",")) {
            if (fileExtension.equals(validExtension)) {
                return true;
            }
        }
        return false;
    }
    private int getOpenParenthesisIndex(String baseFileName) {
        int openParIndex = baseFileName.lastIndexOf("(");
        int closeParIndex = baseFileName.lastIndexOf(")");
        boolean isParenthesis = openParIndex > 0 &&
                closeParIndex == baseFileName.length()-1;

        if (
                isParenthesis &&
                        baseFileName.
                                substring(openParIndex+1, closeParIndex).
                                matches("[1-9][0-9]*")
        ) {
            return openParIndex;
        } else {
            return -1;
        }
    }
    String handleFileName(String fileName, String uploadDirectory)
            throws InvalidFileException {

        String cleanFileName = fileName.replaceAll("[^A-Za-z0-9.()]", "");
        String extension = getFileExtension(cleanFileName);

        if(!isValidExtension(cleanFileName)) {
            throw new InvalidFileException("Invalid File Extension");
        };

        String base = cleanFileName.substring(
                0,
                cleanFileName.length()-extension.length()-1
        );

        int openParIndex = getOpenParenthesisIndex(base);

        if (openParIndex > 0) {
            base = base.substring(0, openParIndex);
            cleanFileName =  base + "." + extension;
        }

        if (Files.exists(Paths.get(uploadDirectory, cleanFileName))) {
            cleanFileName =  base + "(1)." + extension;
        }
        while (Files.exists(Paths.get(uploadDirectory, cleanFileName))) {
            String nString = cleanFileName.substring(
                    base.length()+1,
                    cleanFileName.length()-extension.length()-2
            );
            int n = Integer.parseInt(nString) + 1;
            cleanFileName =  base + "(" + n + ")." + extension;
        }

        return cleanFileName;
    }
    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        this.fileStorageProperties=fileStorageProperties;
        this.fileStorageLoaction = Paths.get(this.fileStorageProperties.getUploadDir()).toAbsolutePath().normalize();

        try {
            // Java 7 新特征
            Files.createDirectories(this.fileStorageLoaction);
        } catch (Exception e) {
            throw new FileStorageException("Could not create the directory where the uploaded files will be stored", e);
        }
    }

    public String storeFile(MultipartFile file) {
        // Normailze file name
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        try {
            if (fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence" + fileName);
            }
            // Copy file to the target loaction (Replacing existing file with the same name
            Path targetLoaction = this.fileStorageLoaction.resolve(fileName);
            Files.copy(file.getInputStream(), targetLoaction, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!",e);
        }
        return fileName;
    }

    public String storeFileByAuth(MultipartFile file, String username, boolean isOverride) throws InvalidFileException {
        // Normailze file name
        // String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        String fileName=null;
        if(isOverride){
            fileName = StringUtils.cleanPath(file.getOriginalFilename());
        }else{
            fileName = this.handleFileName(file.getOriginalFilename(),this.fileStorageLoaction.toString()+File.separator+username);
        }
        System.out.println("fileStorageProperties:"+this.fileStorageLoaction.toString()+File.separator+username);
        String path=null;
        try {
            if (fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence" + fileName);
            }
            // 创建目录
            Files.createDirectories(this.fileStorageLoaction.resolve(username));
            path = username+ File.separator +fileName;
            // Copy file to the target loaction (Replacing existing file with the same name
            Path targetLoaction = this.fileStorageLoaction.resolve(path);
            Files.copy(file.getInputStream(), targetLoaction, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!",e);
        }
        return fileName;
    }


    public Resource loadFileAsResource(String fileName) {
        try {
        Path filePath= this.fileStorageLoaction.resolve(fileName).normalize();
        Resource resource= null;
            resource = new UrlResource(filePath.toUri());
        if(resource.exists()){
            return resource;
        }else{
            throw new MyFileNotFoundException("File not found" +fileName);
        }
        } catch (MalformedURLException e) {
            e.printStackTrace();
            throw new MyFileNotFoundException("File not found" + fileName,e);
        }
    }
    public String  toBase64(String imagePath) {
        String base64Image = "";
        File file = new File(imagePath);
        try (FileInputStream imageInFile = new FileInputStream(file)) {
            // Reading a Image file from file system
            byte imageData[] = new byte[(int) file.length()];
            imageInFile.read(imageData);
            base64Image = Base64.getEncoder().encodeToString(imageData);
        } catch (FileNotFoundException e) {
            System.out.println("Image not found" + e);
        } catch (IOException ioe) {
            System.out.println("Exception while reading the Image " + ioe);
        }
        return base64Image;
    }
    public static void decoder(String base64Image, String pathFile) {
        try (FileOutputStream imageOutFile = new FileOutputStream(pathFile)) {
            // Converting a Base64 String into Image byte array
            byte[] imageByteArray = Base64.getDecoder().decode(base64Image);
            imageOutFile.write(imageByteArray);
        } catch (FileNotFoundException e) {
            System.out.println("Image not found" + e);
        } catch (IOException ioe) {
            System.out.println("Exception while reading the Image " + ioe);
        }
    }
}
